package com.yexx.starter.security.sms;

import com.yexx.core.exception.CommonException;
import com.yexx.starter.security.basic.SecurityUserDetailsService;
import com.yexx.starter.security.basic.constant.SecurityConstants;
import com.yexx.utils.CacheUtil;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;

/**
 * Description: 短信验证码认证provider
 *
 * @author: zuomin (myleszelic@outlook.com)
 * @date: 2020/11/03 14:16
 */
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

    private SecurityUserDetailsService userDetailsService;

    private CacheUtil cacheUtil;

    private String superSmsCode;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;

        //此处写验证短信码
        String key = SecurityConstants.CACHE.LOGIN_SMS_YZM + ":" + authenticationToken.getPrincipal();
        String smsCodeCache = (String) cacheUtil.get(key);
        String smsCodeReq = authentication.getCredentials().toString();

        if (!StringUtils.isEmpty(superSmsCode) && superSmsCode.equals(smsCodeReq)) {
            // 使用超级验证码
        } else if (smsCodeCache == null || !smsCodeCache.equals(smsCodeReq)) {
            throw new InternalAuthenticationServiceException("短信验证码错误,请重新输入");
        }

        //调用自定义的userDetailsService认证
        UserDetails user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
        if (user == null) {
            throw new InternalAuthenticationServiceException("无法获取用户信息");
        }

        //销毁短信验证码，以免别人使用次图像验证码刷接口
        cacheUtil.expire(key, 0);

        Boolean isBind = userDetailsService.checkBindDevice((String) authenticationToken.getPrincipal(), authenticationToken.getDeviceUuid());
        if (!isBind) {
            isBind = userDetailsService.bindDevice(authenticationToken.getPrincipal().toString(), authenticationToken.getDeviceUuid(), authenticationToken.getOsName(), authenticationToken.getOsVersion());
            if (!isBind) {
                throw new CommonException(40021, "无法绑定设备");
            }
        }

        //重新构建UsernamePasswordAuthenticationToken（已认证）
        UsernamePasswordAuthenticationToken authenticationResult = new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());
        authenticationResult.setDetails(authenticationToken.getDetails());
        return authenticationResult;
    }

    /**
     * 只有Authentication为SmsCodeAuthenticationToken使用此Provider认证
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setSecurityUserService(SecurityUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public void setCacheUtil(CacheUtil cacheUtil) {
        this.cacheUtil = cacheUtil;
    }

    public void setSuperSmsCode(String superSmsCode) {
        this.superSmsCode = superSmsCode;
    }

}
